/********************************************************************************
 *    Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH    *
 *                                                                              *
 *              This software is distributed under the terms of the             * 
 *              GNU Lesser General Public Licence (LGPL) version 3,             *  
 *                  copied verbatim in the file "LICENSE"                       *
 ********************************************************************************/
#include "EtfTofw.h"

#include "EtfTofwPoint.h"
#include "EtfTofwGeo.h"
#include "EtfTofwGeoPar.h"

#include "FairVolume.h"
#include "FairGeoVolume.h"
#include "FairGeoNode.h"
#include "FairRootManager.h"
#include "FairGeoLoader.h"
#include "FairGeoInterface.h"
#include "FairRun.h"
#include "FairRuntimeDb.h"
#include "EtfDetectorList.h"
#include "EtfStack.h"

#include "TClonesArray.h"
#include "TVirtualMC.h"
#include "TGeoManager.h"
#include "TGeoBBox.h"
#include "TGeoCompositeShape.h"
#include "TGeoTube.h"
#include "TGeoMaterial.h"
#include "TGeoMedium.h"

#include <iostream>
using std::cout;
using std::endl;

EtfTofw::EtfTofw()
  : FairDetector("EtfTofw", kTRUE, kEtfTofw),
    fTrackID(-1),
    fVolumeID(-1),
		fCopyNo(-1),
    fPos(),
    fMom(),
    fTime(-1.),
    fLength(-1.),
    fELoss(-1),
		fEventNr(0),
    fEtfTofwPointCollection(new TClonesArray("EtfTofwPoint"))
{
}

EtfTofw::EtfTofw(const char* name, Bool_t active)
  : FairDetector(name, active, kEtfTofw),
    fTrackID(-1),
    fVolumeID(-1),
		fCopyNo(-1),
    fPos(),
    fMom(),
    fTime(-1.),
    fLength(-1.),
    fELoss(-1),
		fEventNr(0),
    fEtfTofwPointCollection(new TClonesArray("EtfTofwPoint"))
{
}

EtfTofw::EtfTofw(const EtfTofw& right)
  : FairDetector(right),
    fTrackID(-1),
    fVolumeID(-1),
		fCopyNo(-1),
    fPos(),
    fMom(),
    fTime(-1.),
    fLength(-1.),
    fELoss(-1),
		fEventNr(0),
    fEtfTofwPointCollection(new TClonesArray("EtfTofwPoint"))
{
}

EtfTofw::~EtfTofw()
{
  if (fEtfTofwPointCollection) {
    fEtfTofwPointCollection->Delete();
    delete fEtfTofwPointCollection;
  }
}

void EtfTofw::Initialize()
{
  /**
   * WORKAROUND needed for Geant4 in MT mode
   * Call AddSensitiveVolume for sensitive volumes in order to fill
   * thread-local FairModule::svList.
   */
  DefineSensitiveVolumes();

  FairDetector::Initialize();
  FairRuntimeDb* rtdb= FairRun::Instance()->GetRuntimeDb();
  EtfTofwGeoPar* par=(EtfTofwGeoPar*)(rtdb->getContainer("EtfTofwGeoPar"));
}

Bool_t  EtfTofw::ProcessHits(FairVolume* vol)
{
  /** This method is called from the MC stepping */
		

  //Set parameters at entrance of volume. Reset ELoss.
  if ( TVirtualMC::GetMC()->IsTrackEntering() ) {
    fELoss  = 0.;
    fTime   = TVirtualMC::GetMC()->TrackTime() * 1.0e09;
    fLength = TVirtualMC::GetMC()->TrackLength();
    TVirtualMC::GetMC()->TrackPosition(fPos);
    TVirtualMC::GetMC()->TrackMomentum(fMom);

	
	// --- get Geometry hiearchical Information
		Int_t volid=gMC->CurrentVolID(fCopyNo);
		Int_t cpNo=-1;
		Int_t volid1=gMC->CurrentVolOffID(1,cpNo);
		// cout<<"volid: "<<volid<<", volName: "<<gMC->VolName(volid)<<", volid1: "<<volid1<<", vol1 Name: "<<gMC->VolName(volid1)<<", cpNo: "<<cpNo<<endl;
		// cout<<"hit in strip: "<< fCopyNo << ", hit Pos(" << fPos.X() << ", " << fPos.Y() << ", " << fPos.Z() << ")" << endl;
  }

  // Sum energy loss for all steps in the active volume
  // fELoss += TVirtualMC::GetMC()->Edep()*1000;  // *1000, to change from GeV to MeV
  fELoss += TVirtualMC::GetMC()->Edep();    // GeV

  // Create EtfTofwPoint at exit of active volume
  if ( TVirtualMC::GetMC()->IsTrackExiting()    ||
       TVirtualMC::GetMC()->IsTrackStop()       ||
       TVirtualMC::GetMC()->IsTrackDisappeared()   ) {
    fTrackID  = TVirtualMC::GetMC()->GetStack()->GetCurrentTrackNumber();
    fVolumeID = vol->getMCid();
		

    if (fELoss == 0. ) { return kFALSE; }
		
   
		AddHit(fTrackID, fVolumeID,fCopyNo, TVector3(fPos.X(),  fPos.Y(),  fPos.Z()),
           TVector3(fMom.Px(), fMom.Py(), fMom.Pz()), fTime, fLength,
           fELoss);
		// cout<<"trackID: "<<fTrackID<<", VolumeID: "<<fVolumeID<<", Edep: "<<fELoss<<
			// " MeV, hit Pos: "<<"(" << fPos.X() << ", " << fPos.Y() << ", " << fPos.Z() << ")" << endl;
	
    // Increment number of EtfTofw det points in TParticle
    EtfStack* stack = (EtfStack*) TVirtualMC::GetMC()->GetStack();
    stack->AddPoint(kEtfTofw);
  }

  return kTRUE;
}

void EtfTofw::EndOfEvent()
{

  LOG(info) << "EtfTofw: " << fEtfTofwPointCollection->GetEntriesFast()
            << " points registered in this event";

  fEtfTofwPointCollection->Clear();
	fEventNr++;
}



void EtfTofw::Register()
{

  /** This will create a branch in the output tree called
      EtfTofwPoint, setting the last parameter to kFALSE means:
      this collection will not be written to the file, it will exist
      only during the simulation.
  */

  if ( ! gMC->IsMT() ) {
    FairRootManager::Instance()->Register("EtfTofwPoint", "EtfTofw",
                                          fEtfTofwPointCollection, kTRUE);
  } else {
    FairRootManager::Instance()->RegisterAny("EtfTofwPoint",
                                             fEtfTofwPointCollection, kTRUE);
  }

}


TClonesArray* EtfTofw::GetCollection(Int_t iColl) const
{
  if (iColl == 0) { return fEtfTofwPointCollection; }
  else { return NULL; }
}

void EtfTofw::Reset()
{
  fEtfTofwPointCollection->Clear();
}

void EtfTofw::ConstructGeometry()
{

	TString fileName=GetGeometryFileName();
	if (fileName.EndsWith(".geo")) {
		LOG(info)<<"Constructing geometry from ASCII file "<<fileName;
		ConstructASCIIGeometry();
	} else if (fileName.EndsWith(".root")) {
		LOG(info)<<"Constructing geometry from ROOT file "<<fileName;
		ConstructRootGeometry();
	} else {
		LOG(fatal) << "Geometry format not supported.";
	}
}

EtfTofwPoint* EtfTofw::AddHit(Int_t trackID, Int_t detID,Int_t copyNo,
                                      TVector3 pos, TVector3 mom,
                                      Double_t time, Double_t length,
                                      Double_t eLoss)
{
  TClonesArray& clref = *fEtfTofwPointCollection;
  Int_t size = clref.GetEntriesFast();
	EtfTofwPoint* myPoint= new(clref[size]) EtfTofwPoint(trackID, detID, copyNo, pos, mom, time, length, eLoss);
	/*
	myPoint->SetLink(FairLink(-1, fEventNr, FairRootManager::Instance()->GetBranchId("GeoTracks"), trackID));
	// myPoint->SetLink(FairLink(-1, fEventNr, FairRootManager::Instance()->GetBranchId("MCTrack"), trackID));
	cout<<" fEventNr:"<<fEventNr<<endl;
	cout<<"FairRootManager::Instance()->GetBranchId(\"MCTrack\")"<<FairRootManager::Instance()->GetBranchId("MCTrack")<<endl;
	cout<<"FairRootManager::Instance()->GetBranchId(\"GeoTracks\")"<<FairRootManager::Instance()->GetBranchId("GeoTracks")<<endl;
	*/
	return myPoint;
}

FairModule* EtfTofw::CloneModule() const
{
  return new EtfTofw(*this);
}

void EtfTofw::DefineSensitiveVolumes()
{
  TObjArray* volumes = gGeoManager->GetListOfVolumes();
  TIter next(volumes);
  TGeoVolume* volume;
	cout<<" cout from EtfTofw.cxx"<<endl;
  while ( ( volume = static_cast<TGeoVolume*>(next()) ) ) {
    if ( CheckIfSensitive(volume->GetName()) ) {
      LOG(debug2)<<"Sensitive Volume "<< volume->GetName();
      AddSensitiveVolume(volume);
    }
  }
}

Bool_t EtfTofw::CheckIfSensitive(std::string name)
{
		// cout<<"check if sensitive, for "<< name<<endl;

  if(TString(name).Contains("TOFW_module"))
  {
		cout<<"TOFwall is sensitive"<<endl;
    return kTRUE;
  }
	// cout<<"it is not sensitive"<<endl;
  return kFALSE;
}

ClassImp(EtfTofw)
